﻿#include "stdafx.h"
#ifdef LK_WINDOWS_WAS_DEVICECHANGECALLBACK_
namespace LK
{
	namespace Windows
	{
		namespace WAS
		{
			//DeviceChangeCallback类
			ULONG STDMETHODCALLTYPE DeviceChangeCallback::AddRef()
			{
				return InterlockedIncrement(&_cRef);//引用计数增加
			}
			ULONG STDMETHODCALLTYPE DeviceChangeCallback::Release()
			{
				ULONG ulRef = InterlockedDecrement(&_cRef);
				if (0 == ulRef)
				{//不执行删除
				}
				return ulRef;
			}
			HRESULT STDMETHODCALLTYPE DeviceChangeCallback::QueryInterface(REFIID riid, VOID **ppvInterface)
			{
				if (IID_IUnknown == riid)
				{
					AddRef();
					*ppvInterface = (IUnknown*)this;
				}
				else if (__uuidof(IMMNotificationClient) == riid)
				{
					AddRef();
					*ppvInterface = (IMMNotificationClient*)this;
				}
				else
				{
					*ppvInterface = NULL;
					return E_NOINTERFACE;
				}
				return S_OK;
			}
			HRESULT STDMETHODCALLTYPE DeviceChangeCallback::OnDeviceAdded(LPCWSTR pwstrDeviceId)
			{
				InterlockedIncrement(&SoundEnvironment::GetDefaultRef().changedCount);
				if (!SoundEnvironment::GetDefaultRef().soundtc.Try())
				{
					if (InterlockedIncrement(&count) > 1){ InterlockedDecrement(&count); return 0; }
					SoundEnvironment::GetDefaultRef().soundtc.Lock();
				}
				SoundEnvironment::GetDefaultRef().OnAddedDeviceId = pwstrDeviceId;
				for (int i = 0; i < SoundEnvironment::GetDefaultRef().speakerList.Length; ++i)Threading::StartThread(SoundEnvironment::GetDefaultRef().speakerList[i], &Speaker::OnDeviceAdded);
				for (int i = 0; i < SoundEnvironment::GetDefaultRef().recorderList.Length; ++i)Threading::StartThread(SoundEnvironment::GetDefaultRef().recorderList[i], &Recorder::OnDeviceAdded);
				InterlockedDecrement(&count);
				SoundEnvironment::GetDefaultRef().soundtc.UnLock();
#ifdef LK_FUNCTIONAL_ACTION_
				if (SoundEnvironment::GetDefaultRef().OnDeviceAdded!=null)
				{
					LK::ptr<Collection::IArray<ptr<Object>>>arr(1);
					arr[0] = ptr<String>(pwstrDeviceId);
					arr[0].UseCount.SetEnableThreadSafe(true);
					ptr<LK::Functional::IActions>  act(SoundEnvironment::GetDefaultRef().OnDeviceAdded, arr);
					act.DoSync();
				}
#endif
				return 0;
			}
			HRESULT STDMETHODCALLTYPE DeviceChangeCallback::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState)
			{
				InterlockedIncrement(&SoundEnvironment::GetDefaultRef().changedCount);
				if (!SoundEnvironment::GetDefaultRef().soundtc.Try())
				{
					if (InterlockedIncrement(&count) > 1){ InterlockedDecrement(&count); return 0; }
					SoundEnvironment::GetDefaultRef().soundtc.Lock();
				}
				SoundEnvironment::GetDefaultRef().OnStateChangedDeviceId = pwstrDeviceId;
				SoundEnvironment::GetDefaultRef().OnStateChangedNewState = dwNewState;
				for (int i = 0; i < SoundEnvironment::GetDefaultRef().speakerList.Length; ++i)Threading::StartThread(SoundEnvironment::GetDefaultRef().speakerList[i], &Speaker::OnDeviceStateChanged);
				for (int i = 0; i < SoundEnvironment::GetDefaultRef().recorderList.Length; ++i)Threading::StartThread(SoundEnvironment::GetDefaultRef().recorderList[i], &Recorder::OnDeviceStateChanged);
				InterlockedDecrement(&count);
				SoundEnvironment::GetDefaultRef().soundtc.UnLock();
#ifdef LK_FUNCTIONAL_ACTION_
				if (SoundEnvironment::GetDefaultRef().OnDeviceStateChanged!=null)
				{
					LK::ptr<Collection::IArray<ptr<Object>>>arr(2);
					arr[0] = ptr<String>(pwstrDeviceId);
					arr[1] = dwNewState;
					arr[0].UseCount.SetEnableThreadSafe(true);
					arr[1].UseCount.SetEnableThreadSafe(true);
					ptr<LK::Functional::IActions>  act(SoundEnvironment::GetDefaultRef().OnDeviceStateChanged, arr);
					act.DoSync();
				}
#endif
				return 0;
			}
			HRESULT STDMETHODCALLTYPE DeviceChangeCallback::OnDeviceRemoved(LPCWSTR pwstrDeviceId)
			{
				InterlockedIncrement(&SoundEnvironment::GetDefaultRef().changedCount);
				if (!SoundEnvironment::GetDefaultRef().soundtc.Try())
				{
					if (InterlockedIncrement(&count) > 1){ InterlockedDecrement(&count); return 0; }
					SoundEnvironment::GetDefaultRef().soundtc.Lock();
				}
				SoundEnvironment::GetDefaultRef().OnRemovedDeviceId = pwstrDeviceId;
				for (int i = 0; i < SoundEnvironment::GetDefaultRef().speakerList.Length; ++i)Threading::StartThread(SoundEnvironment::GetDefaultRef().speakerList[i], &Speaker::OnDeviceRemoved);
				for (int i = 0; i < SoundEnvironment::GetDefaultRef().recorderList.Length; ++i)Threading::StartThread(SoundEnvironment::GetDefaultRef().recorderList[i], &Recorder::OnDeviceRemoved);
				InterlockedDecrement(&count);
				SoundEnvironment::GetDefaultRef().soundtc.UnLock();
#ifdef LK_FUNCTIONAL_ACTION_
				if (SoundEnvironment::GetDefaultRef().OnDeviceRemoved!=null)
				{
					LK::ptr<Collection::IArray<ptr<Object>>>arr(1);
					arr[0] = ptr<String>(pwstrDeviceId);
					arr[0].UseCount.SetEnableThreadSafe(true);
					ptr<LK::Functional::IActions>  act(SoundEnvironment::GetDefaultRef().OnDeviceRemoved, arr);
					act.DoSync();
				}
#endif
				return 0;
			}
			HRESULT STDMETHODCALLTYPE DeviceChangeCallback::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId)
			{
				InterlockedIncrement(&SoundEnvironment::GetDefaultRef().changedCount);
				if (!SoundEnvironment::GetDefaultRef().soundtc.Try())
				{
					if (InterlockedIncrement(&count) > 1){ InterlockedDecrement(&count); return 0; }
					SoundEnvironment::GetDefaultRef().soundtc.Lock();
				}
				SoundEnvironment::GetDefaultRef().OnDefaultChangedFlow = flow;
				SoundEnvironment::GetDefaultRef().OnDefaultChangedRole = role;
				SoundEnvironment::GetDefaultRef().OnDefaultChangedDeviceId = pwstrDefaultDeviceId;
				if (flow == eRender)for (int i = 0; i < SoundEnvironment::GetDefaultRef().speakerList.Length; ++i)Threading::StartThread(SoundEnvironment::GetDefaultRef().speakerList[i], &Speaker::OnDefaultDeviceChanged);
				if (flow == eCapture)for (int i = 0; i < SoundEnvironment::GetDefaultRef().recorderList.Length; ++i)Threading::StartThread(SoundEnvironment::GetDefaultRef().recorderList[i], &Recorder::OnDefaultDeviceChanged);
				InterlockedDecrement(&count);
				SoundEnvironment::GetDefaultRef().soundtc.UnLock();
#ifdef LK_FUNCTIONAL_ACTION_
				if (SoundEnvironment::GetDefaultRef().OnDefaultDeviceChanged!=null)
				{
					LK::ptr<Collection::IArray<ptr<Object>>>arr(3);
					arr[0] = flow;
					arr[1] = role;
					arr[2] = ptr<String>(pwstrDefaultDeviceId);
					arr[0].UseCount.SetEnableThreadSafe(true);
					arr[1].UseCount.SetEnableThreadSafe(true);
					arr[2].UseCount.SetEnableThreadSafe(true);
					ptr<LK::Functional::IActions>  act(SoundEnvironment::GetDefaultRef().OnDefaultDeviceChanged, arr);
					act.DoSync();
				}
#endif
				return 0;
			}
			HRESULT STDMETHODCALLTYPE DeviceChangeCallback::OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key)
			{
				InterlockedIncrement(&SoundEnvironment::GetDefaultRef().changedCount);
				if (!SoundEnvironment::GetDefaultRef().soundtc.Try())
				{
					if (InterlockedIncrement(&count) > 1){ InterlockedDecrement(&count); return 0; }
					SoundEnvironment::GetDefaultRef().soundtc.Lock();
				}
				SoundEnvironment::GetDefaultRef().OnPropertyValueChangedDeviceId = pwstrDeviceId;
				SoundEnvironment::GetDefaultRef().OnPropertyValueChangedKey = key;
				for (int i = 0; i < SoundEnvironment::GetDefaultRef().speakerList.Length; ++i)Threading::StartThread(SoundEnvironment::GetDefaultRef().speakerList[i], &Speaker::OnDevicePropertyValueChanged);
				for (int i = 0; i < SoundEnvironment::GetDefaultRef().recorderList.Length; ++i)Threading::StartThread(SoundEnvironment::GetDefaultRef().recorderList[i], &Recorder::OnDevicePropertyValueChanged);
				InterlockedDecrement(&count);
				SoundEnvironment::GetDefaultRef().soundtc.UnLock();
#ifdef LK_FUNCTIONAL_ACTION_
				if (SoundEnvironment::GetDefaultRef().OnPropertyValueChanged!=null)
				{
					LK::ptr<Collection::IArray<ptr<Object>>>arr(2);
					arr[0] = ptr<String>(pwstrDeviceId);
					arr[1] = key;
					arr[0].UseCount.SetEnableThreadSafe(true);
					arr[1].UseCount.SetEnableThreadSafe(true);
					ptr<LK::Functional::IActions>  act(SoundEnvironment::GetDefaultRef().OnPropertyValueChanged, arr);
					act.DoSync();
				}
#endif
				return 0;
			}
		}
	}
}
#endif